local Util			= require("common.Util")
local SkillExcel	= require("excel.Skill").Skill
local UtilityExcel	= require("excel.Skill").Utility
local SkillDefine	= require("skill.Define")
local Skill			= require("skill.Skill")
local Obj			= require("core.Obj")
local SceneEvent	= require("core.SceneEvent")
local Map			= require("core.Map")
local ObjMonster	= require("core.ObjMonster")

local argsTemp			= {}

local sqrt				= math.sqrt

----------------- 位置修正 --------------------
function fixActionType(unit)
  local utilityConfig = unit.utilityConfig
  local args = utilityConfig.actionArg
  if #args<1 or utilityConfig.multiTarget~=0 then return end
  if utilityConfig.actionType==SkillDefine.ACTION_TYPE_LINE or utilityConfig.actionType==SkillDefine.ACTION_TYPE_PARABOLA then
    local currentLen = Util.dist(unit.x,unit.y,unit.mouseX,unit.mouseY)
    local maxLen = (args[1]~=nil and args[1]>0) and args[1]
    local is8Dir = args[2]==1
    
    if is8Dir or currentLen <= 0 then
        unit.tx,unit.ty = Util.getAnglePoint(unit.dir,unit.x,unit.y,0,maxLen and maxLen or currentLen)
    elseif maxLen then
        unit.tx,unit.ty = Util.getAnglePoint2(unit.x,unit.y,unit.mouseX,unit.mouseY,maxLen)
    end
  end
end

--acttackType 为4 ： 以前方朝向计算tx,ty
function fixDirAttackType(obj, skillID, skillConfig, x, y, tx, ty)
  local utilityConfig = UtilityExcel[skillConfig.mainUtility]
  if not utilityConfig then return tx,ty end
  if utilityConfig.acttackType ~= SkillDefine.ACTTACK_TYPE_DIR or not obj.dir then
      return tx, ty
  end
  local len = getAttackLen(skillID)
  local ttx,tty = Util.getAnglePoint(obj.dir,x,y,0, len)
  return ttx, tty
end


function handler(obj, skillID, skillConfig, x, y, tx, ty, target, level)
	local utilityConfig = UtilityExcel[skillConfig.mainUtility]
	if not utilityConfig then return tx,ty end
	
	local callback = _ENV[utilityConfig.utility]
	if callback then
		return callback(obj, skillID, skillConfig, utilityConfig, x, y, tx, ty, target, level)
	elseif utilityConfig.actionType == SkillDefine.ACTION_TYPE_FAN_SPREAD_COMBO then
		return fanSpreadCombo(obj, skillID, skillConfig, utilityConfig, x, y, tx, ty, target, level)
	end
	return tx,ty
end

function jumpTo(obj, skillID, skillConfig, utilityConfig, x, y, tx, ty, target, level)
	local len		= getAttackLen(skillID)
	local dx		= tx - x
	local dy		= ty - y
	local sceneID	= obj.scene_id
	local mainUtilityArgs = skillConfig.mainUtilityArgs
	local args = mainUtilityArgs[level] or mainUtilityArgs[#mainUtilityArgs] or argsTemp 
	local maxLen,fixed  = args[1],args[2]
	if fixed == 1 then
	   tx, ty = Util.getTargetPoint(tx,ty,x,y,maxLen)
	else
	   if maxLen then 
	       len = maxLen
	   end
	        
	   local curLen	= sqrt(dx * dx + dy * dy)		
	   -- 超出释放距离 则截断
	   if curLen > len  then
		    tx, ty = x + dx * len / curLen, y + dy * len / curLen
	   elseif curLen > 26 then
		    local spacing = curLen - 25
		    tx, ty = dx * spacing / curLen + x, dy * spacing / curLen + y	
	   end
	end	
	SceneEvent.setBan(sceneID)
	tx, ty = Map.through_jump(sceneID, x, y, tx, ty)
	return tx, ty
end

function rush(obj, skillID, skillConfig, utilityConfig, x, y, tx, ty, target, level)
	local mainUtilityArgs = skillConfig.mainUtilityArgs
	local args	= mainUtilityArgs[level] or mainUtilityArgs[#mainUtilityArgs] or argsTemp	
	
	 local canRushBlock  = args[1]==1    -- 是否能冲出障碍
  local fixedLen    = args[2]     -- 固定距离
  local isPush    = args[3]==1    -- 是否推人
  local pushLen   = args[4] or 0    -- 推人距离
	local sceneID		= obj.scene_id
	
	SceneEvent.setBan(sceneID)
	if isPush and target and target.monster_id  and ObjMonster.getValueByMonsterType(target, "can_hit_back_fly")  == 0  then
		isPush = false --怪物不能被推
  elseif isPush and target and obj.obj_type == Obj.TYPE_HUMAN and target.obj_type == Obj.TYPE_HUMAN and target.db.lv >obj.db.lv  then
	  isPush = false --PVP时，不能推等级比自己高的人
	end
	
	if fixedLen and fixedLen >0 then
	  if not isPush and target and utilityConfig.acttackType == SkillDefine.ACTTACK_TYPE_LOCK_TARGET then --锁定目标且固定距离的需停在目标点
        tx,ty = Util.getTargetPoint(x,y, target.x, target.y, Obj.getRadius(target) + Obj.getRadius(obj)) 
	  else	     
	      if not canRushBlock and target then
	           local nx, ny = Map.through(sceneID, x, y, tx, ty)
	           if nx == tx and ny == ty then
	              tx, ty = Util.getTargetPoint(tx,ty,x,y,fixedLen) 
	           else
	              target = nil
 	           end
	      else
		         tx, ty = Util.getTargetPoint(tx,ty,x,y,fixedLen)	
		    end
		end	
	else
		if utilityConfig.acttackType == SkillDefine.ACTTACK_TYPE_SELF then
			tx,ty = x,y
		else
			local len = getAttackLen(skillID)
			if utilityConfig.acttackType == SkillDefine.ACTTACK_TYPE_LOCK_TARGET then
				if target then					
					local newTx,newTy					
					if canRushBlock then
						newTx, newTy = Map.through_jump(sceneID, x, y, target.x, target.y)
					else
						newTx, newTy = Map.through(sceneID, x, y, target.x, target.y)
					end					
					if not(newTx==target.x and newTy==target.y) then	--不可通行 技能失效
						return tx,ty,true
					end					
					if not isPush then
						pushLen = 0
					else
						len = len + pushLen
					end
					tx,ty = Util.getTargetPoint(x,y, target.x, target.y, Obj.getRadius(target) + Obj.getRadius(obj) - pushLen)	--�Ƶľ���
				else
					tx, ty = x, y
				end
			end			
			local dx = tx - x
			local dy = ty - y
			local curLen = sqrt(dx * dx + dy * dy)
			-- 超出释放距离 则截断
			if curLen > len  then
				tx, ty = x + dx * len / curLen, y + dy * len / curLen
			end
		end
	end

	if canRushBlock then	 
		tx, ty = Map.through_jump(sceneID, x, y, tx, ty)
	else
		tx, ty = Map.through(sceneID, x, y, tx, ty)
	end

	if obj.obj_type == Obj.TYPE_HUMAN then
		obj.rushx = tx
		obj.rushy = ty
	end
	
	local userData = Skill.getUserData(obj)	
	if isPush and target then
	  local dist = Util.dist(x,y,tx,ty)
	  if dist > Obj.getRadius(target) + Obj.getRadius(obj) then
	     dist = Obj.getRadius(target) + Obj.getRadius(obj)
	  end
		local stopX,stopY = Util.getTargetPoint(x, y, tx, ty, dist)
		
		if canRushBlock then
			userData[1], userData[2] = Map.through_jump(sceneID, x, y, stopX, stopY)
		else
			userData[1], userData[2] = Map.through(sceneID, x, y, stopX, stopY)
		end
		if stopX~=userData[1] or userData[2]~=stopY or (x==stopX and y==stopY)  then	
			userData[3] = true
		end
		userData[4]  = true
	else
		userData[4] = false
	end
	return tx,ty
end

function jump(obj, skillID, skillConfig, utilityConfig, x, y, tx, ty, target, level)
	local mainUtilityArgs = skillConfig.mainUtilityArgs
	local args	= mainUtilityArgs[level] or mainUtilityArgs[#mainUtilityArgs] or argsTemp	
	
	local sceneID		= obj.scene_id
	local maxLen,fixed  = args[1],args[2]
		
	if fixed==1 then	-- 是否固定距离
		tx, ty = Util.getTargetPoint(tx,ty,x,y,maxLen)
	else
		local len = maxLen
		local dx = tx - x
		local dy = ty - y
		local curLen = sqrt(dx * dx + dy * dy)	
	
		-- 超出释放距离 则截断
		if curLen > len  then
			tx, ty = x + dx * len / curLen, y + dy * len / curLen
		end
	end
	SceneEvent.setBan(sceneID)
	tx, ty = Map.through_jump(sceneID, x, y, tx, ty)
	return tx, ty
end

-- 环形扩散组合
function fanSpreadCombo(obj, skillID, skillConfig, utilityConfig, x, y, tx, ty)--, target, level)
	local radius = utilityConfig.aoeArgs[1]
	tx, ty = Util.getTargetPoint(tx, ty, x, y, radius)
	return tx, ty
end

function getAttackLen(skillID)
	local config = SkillExcel[skillID]
	return UtilityExcel[config.mainUtility].mouseToSelf
end